<script setup lang="ts">
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useElementSize, useResizeObserver } from '@vueuse/core';
import type { TabOptions, UserAction } from '@n8n/design-system';
import { useI18n } from '@n8n/i18n';
import { ProjectTypes } from '../projects.types';
import { useProjectsStore } from '../projects.store';
import ProjectTabs from './ProjectTabs.vue';
import ProjectIcon from './ProjectIcon.vue';
import { getResourcePermissions } from '@n8n/permissions';
import { EnterpriseEditionFeature, VIEWS } from '@/app/constants';
import { useSourceControlStore } from '@/features/integrations/sourceControl.ee/sourceControl.store';
import ProjectCreateResource from './ProjectCreateResource.vue';
import { useSettingsStore } from '@/app/stores/settings.store';
import { useProjectPages } from '@/features/collaboration/projects/composables/useProjectPages';
import { truncateTextToFitWidth } from '@/app/utils/formatters/textFormatter';
import { type IconName } from '@n8n/design-system/components/N8nIcon/icons';
import type { IUser } from 'n8n-workflow';
import { type IconOrEmoji, isIconOrEmoji } from '@n8n/design-system/components/N8nIconPicker/types';
import { useUIStore } from '@/app/stores/ui.store';
import { PROJECT_DATA_TABLES } from '@/features/core/dataTable/constants';
import ReadyToRunButton from '@/features/workflows/readyToRun/components/ReadyToRunButton.vue';

import { N8nButton, N8nHeading, N8nText, N8nTooltip } from '@n8n/design-system';
import { VARIABLE_MODAL_KEY } from '@/features/settings/environments.ee/environments.constants';
import { useTelemetry } from '@/app/composables/useTelemetry';
import { useUsersStore } from '@/features/settings/users/users.store';
const route = useRoute();
const router = useRouter();
const i18n = useI18n();
const projectsStore = useProjectsStore();
const sourceControlStore = useSourceControlStore();
const settingsStore = useSettingsStore();
const uiStore = useUIStore();
const telemetry = useTelemetry();
const usersStore = useUsersStore();

const projectPages = useProjectPages();

const props = defineProps<{
	hasActiveCallouts?: boolean;
	mainButton?: ActionTypes;
}>();

const emit = defineEmits<{
	createFolder: [];
}>();

const headerIcon = computed((): IconOrEmoji => {
	if (projectsStore.currentProject?.type === ProjectTypes.Personal) {
		return { type: 'icon', value: 'user' };
	} else if (projectsStore.currentProject?.name) {
		return isIconOrEmoji(projectsStore.currentProject.icon)
			? projectsStore.currentProject.icon
			: { type: 'icon', value: 'layers' };
	} else {
		return { type: 'icon', value: 'house' };
	}
});

const homeProject = computed(() => projectsStore.currentProject ?? projectsStore.personalProject);

const isPersonalProject = computed(() => {
	return homeProject.value?.type === ProjectTypes.Personal;
});

const projectName = computed(() => {
	if (!projectsStore.currentProject) {
		if (projectPages.isSharedSubPage) {
			return i18n.baseText('projects.header.shared.title');
		} else if (projectPages.isOverviewSubPage) {
			return i18n.baseText('projects.menu.overview');
		} else if (isPersonalProject.value) {
			return i18n.baseText('projects.menu.personal');
		}
		return null;
	} else if (projectsStore.currentProject.type === ProjectTypes.Personal) {
		return i18n.baseText('projects.menu.personal');
	} else {
		return projectsStore.currentProject.name;
	}
});

const projectPermissions = computed(
	() => getResourcePermissions(projectsStore.currentProject?.scopes).project,
);
const projectVariablePermissions = computed(
	() => getResourcePermissions(projectsStore.currentProject?.scopes).projectVariable,
);
const globalVariablesPermissions = computed(
	() => getResourcePermissions(usersStore.currentUser?.globalScopes).variable,
);

const showSettings = computed(
	() =>
		!!route?.params?.projectId &&
		!!projectPermissions.value.update &&
		projectsStore.currentProject?.type === ProjectTypes.Team,
);

const showFolders = computed(() => {
	return (
		settingsStore.isFoldersFeatureEnabled &&
		[VIEWS.PROJECTS_WORKFLOWS, VIEWS.PROJECTS_FOLDERS].includes(route.name as VIEWS)
	);
});

const customProjectTabs = computed((): Array<TabOptions<string>> => {
	// Determine the type of tab based on the current project page
	let tabType: 'shared' | 'overview' | 'project';
	if (projectPages.isSharedSubPage) {
		tabType = 'shared';
	} else if (projectPages.isOverviewSubPage) {
		tabType = 'overview';
	} else {
		tabType = 'project';
	}
	// Only pick up tabs from active modules
	const activeModules = Object.keys(uiStore.moduleTabs[tabType]).filter(
		settingsStore.isModuleActive,
	);
	return activeModules.flatMap((module) => uiStore.moduleTabs[tabType][module]);
});

const ACTION_TYPES = {
	WORKFLOW: 'workflow',
	CREDENTIAL: 'credential',
	FOLDER: 'folder',
	DATA_TABLE: 'dataTable',
	VARIABLE: 'variable',
} as const;
type ActionTypes = (typeof ACTION_TYPES)[keyof typeof ACTION_TYPES];

const createWorkflowButton = computed(() => ({
	value: ACTION_TYPES.WORKFLOW,
	label: i18n.baseText('projects.header.create.workflow'),
	icon: sourceControlStore.preferences.branchReadOnly ? ('lock' as IconName) : undefined,
	size: 'mini' as const,
	disabled:
		sourceControlStore.preferences.branchReadOnly ||
		!getResourcePermissions(homeProject.value?.scopes).workflow.create,
}));

const createCredentialButton = computed(() => ({
	value: ACTION_TYPES.CREDENTIAL,
	label: i18n.baseText('projects.header.create.credential'),
	icon: sourceControlStore.preferences.branchReadOnly ? ('lock' as IconName) : undefined,
	size: 'mini' as const,
	disabled:
		sourceControlStore.preferences.branchReadOnly ||
		!getResourcePermissions(homeProject.value?.scopes).credential.create,
}));

const createDataTableButton = computed(() => ({
	value: ACTION_TYPES.DATA_TABLE,
	label: i18n.baseText('dataTable.add.button.label'),
	icon: sourceControlStore.preferences.branchReadOnly ? ('lock' as IconName) : undefined,
	size: 'mini' as const,
	disabled:
		sourceControlStore.preferences.branchReadOnly ||
		!getResourcePermissions(homeProject.value?.scopes)?.dataTable?.create,
}));

const createVariableButton = computed(() => ({
	value: ACTION_TYPES.VARIABLE,
	label: i18n.baseText('variables.add.button.label'),
	icon: sourceControlStore.preferences.branchReadOnly ? ('lock' as IconName) : undefined,
	size: 'mini' as const,
	disabled:
		sourceControlStore.preferences.branchReadOnly ||
		(!projectVariablePermissions.value.create && !globalVariablesPermissions.value.create),
}));

const selectedMainButtonType = computed(() => props.mainButton ?? ACTION_TYPES.WORKFLOW);

const mainButtonConfig = computed(() => {
	switch (selectedMainButtonType.value) {
		case ACTION_TYPES.CREDENTIAL:
			return createCredentialButton.value;
		case ACTION_TYPES.DATA_TABLE:
			return createDataTableButton.value;
		case ACTION_TYPES.VARIABLE:
			return createVariableButton.value;
		case ACTION_TYPES.WORKFLOW:
		default:
			return createWorkflowButton.value;
	}
});

const menu = computed(() => {
	const items: Array<UserAction<IUser>> = [];

	// Add workflow to menu if it's not the main button
	if (selectedMainButtonType.value !== ACTION_TYPES.WORKFLOW) {
		items.push({
			value: ACTION_TYPES.WORKFLOW,
			label: i18n.baseText('projects.header.create.workflow'),
			disabled:
				sourceControlStore.preferences.branchReadOnly ||
				!getResourcePermissions(homeProject.value?.scopes).workflow.create,
		});
	}

	// Add credential to menu if it's not the main button
	if (selectedMainButtonType.value !== ACTION_TYPES.CREDENTIAL) {
		items.push({
			value: ACTION_TYPES.CREDENTIAL,
			label: i18n.baseText('projects.header.create.credential'),
			disabled:
				sourceControlStore.preferences.branchReadOnly ||
				!getResourcePermissions(homeProject.value?.scopes).credential.create,
		});
	}

	if (
		selectedMainButtonType.value !== ACTION_TYPES.VARIABLE &&
		settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables]
	) {
		items.push({
			value: ACTION_TYPES.VARIABLE,
			label: i18n.baseText('variables.add.button.label'),
			disabled:
				sourceControlStore.preferences.branchReadOnly ||
				!getResourcePermissions(homeProject.value?.scopes).projectVariable.create,
		});
	}

	if (showFolders.value) {
		items.push({
			value: ACTION_TYPES.FOLDER,
			label: i18n.baseText('projects.header.create.folder'),
			disabled:
				sourceControlStore.preferences.branchReadOnly ||
				!getResourcePermissions(homeProject.value?.scopes).folder.create,
		});
	}

	if (
		settingsStore.isDataTableFeatureEnabled &&
		selectedMainButtonType.value !== ACTION_TYPES.DATA_TABLE
	) {
		// TODO: this should probably be moved to the module descriptor as a setting
		items.push({
			value: ACTION_TYPES.DATA_TABLE,
			label: i18n.baseText('dataTable.add.button.label'),
			disabled:
				sourceControlStore.preferences.branchReadOnly ||
				!getResourcePermissions(homeProject.value?.scopes)?.dataTable?.create,
		});
	}

	return items;
});

const showProjectIcon = computed(() => {
	return (
		!projectPages.isOverviewSubPage && !projectPages.isSharedSubPage && !isPersonalProject.value
	);
});

function isCredentialsListView(routeName: string) {
	const CREDENTIAL_VIEWS: string[] = [
		VIEWS.PROJECTS_CREDENTIALS,
		VIEWS.CREDENTIALS,
		VIEWS.SHARED_CREDENTIALS,
	];

	return CREDENTIAL_VIEWS.includes(routeName);
}

function isWorkflowListView(routeName: string) {
	const WORKFLOWS_VIEWS: string[] = [
		VIEWS.PROJECTS_WORKFLOWS,
		VIEWS.WORKFLOWS,
		VIEWS.SHARED_WORKFLOWS,
		VIEWS.PROJECTS_FOLDERS,
	];

	return WORKFLOWS_VIEWS.includes(routeName);
}

function getUIContext(routeName: string) {
	if (isCredentialsListView(routeName)) {
		return 'credentials_list';
	} else if (isWorkflowListView(routeName)) {
		return 'workflow_list';
	} else {
		return;
	}
}

const actions: Record<ActionTypes, (projectId: string) => void> = {
	[ACTION_TYPES.WORKFLOW]: (projectId: string) => {
		void router.push({
			name: VIEWS.NEW_WORKFLOW,
			query: {
				projectId,
				parentFolderId: route.params.folderId as string,
				uiContext: getUIContext(route.name?.toString() ?? ''),
			},
		});
	},
	[ACTION_TYPES.CREDENTIAL]: (projectId: string) => {
		void router.push({
			name: VIEWS.PROJECTS_CREDENTIALS,
			params: {
				projectId,
				credentialId: 'create',
			},
			query: {
				uiContext: getUIContext(route.name?.toString() ?? ''),
			},
		});
	},
	[ACTION_TYPES.FOLDER]: () => {
		emit('createFolder');
	},
	[ACTION_TYPES.DATA_TABLE]: (projectId: string) => {
		void router.push({
			name: PROJECT_DATA_TABLES,
			params: { projectId, new: 'new' },
		});
	},
	[ACTION_TYPES.VARIABLE]: () => {
		uiStore.openModalWithData({ name: VARIABLE_MODAL_KEY, data: { mode: 'new' } });
		telemetry.track('User clicked header add variable button');
	},
} as const;

const pageType = computed(() => {
	if (projectPages.isSharedSubPage) {
		return 'shared';
	} else if (projectPages.isOverviewSubPage) {
		return 'overview';
	} else {
		return 'project';
	}
});

const sectionDescription = computed(() => {
	if (projectPages.isSharedSubPage) {
		return i18n.baseText('projects.header.shared.subtitle');
	} else if (projectPages.isOverviewSubPage) {
		return i18n.baseText(
			settingsStore.isDataTableFeatureEnabled
				? 'projects.header.overview.subtitleWithDataTables'
				: 'projects.header.overview.subtitle',
		);
	} else if (isPersonalProject.value) {
		return i18n.baseText(
			settingsStore.isDataTableFeatureEnabled
				? 'projects.header.personal.subtitleWithDataTables'
				: 'projects.header.personal.subtitle',
		);
	}

	return null;
});

const projectDescription = computed(() => {
	if (projectPages.isProjectsSubPage) {
		return projectsStore.currentProject?.description;
	}

	return null;
});

const projectHeaderRef = ref<HTMLElement | null>(null);
const { width: projectHeaderWidth } = useElementSize(projectHeaderRef);

const headerActionsRef = ref<HTMLElement | null>(null);
const { width: headerActionsWidth } = useElementSize(headerActionsRef);

const projectSubtitleFontSizeInPxs = ref<number | null>(null);

useResizeObserver(projectHeaderRef, () => {
	if (!projectHeaderRef.value) {
		return;
	}

	const projectSubtitleEl = projectHeaderRef.value.querySelector(
		'span[data-test-id="project-subtitle"]',
	);
	if (projectSubtitleEl) {
		const computedStyle = window.getComputedStyle(projectSubtitleEl);
		projectSubtitleFontSizeInPxs.value = parseFloat(computedStyle.fontSize);
	}
});

const projectDescriptionTruncated = computed(() => {
	if (!projectDescription.value) {
		return '';
	}

	const availableTextWidth = projectHeaderWidth.value - headerActionsWidth.value;
	// Fallback to N8nText component default font-size, small
	const fontSizeInPixels = projectSubtitleFontSizeInPxs.value ?? 14;
	return truncateTextToFitWidth(projectDescription.value, availableTextWidth, fontSizeInPixels);
});

const onSelect = (action: string) => {
	const executableAction = actions[action as ActionTypes];
	if (!homeProject.value) {
		return;
	}

	executableAction(homeProject.value.id);
};
</script>

<template>
	<div>
		<div ref="projectHeaderRef" :class="$style.projectHeader">
			<div :class="$style.projectDetails">
				<ProjectIcon v-if="showProjectIcon" :icon="headerIcon" :border-less="true" size="medium" />
				<div :class="$style.headerActions">
					<N8nHeading v-if="projectName" bold tag="h2" size="xlarge" data-test-id="project-name">{{
						projectName
					}}</N8nHeading>
					<N8nText v-if="sectionDescription" color="text-light" data-test-id="project-subtitle">
						{{ sectionDescription }}
					</N8nText>
					<template v-else-if="projectDescription">
						<div :class="$style.projectDescriptionWrapper">
							<N8nText color="text-light" data-test-id="project-subtitle">
								{{ projectDescriptionTruncated || projectDescription }}
							</N8nText>
							<div v-if="projectDescriptionTruncated" :class="$style.tooltip">
								<N8nText color="text-light">{{ projectDescription }}</N8nText>
							</div>
						</div>
					</template>
				</div>
			</div>
			<div
				v-if="route.name !== VIEWS.PROJECT_SETTINGS"
				ref="headerActionsRef"
				:class="[$style.headerActions]"
			>
				<N8nTooltip
					:disabled="!sourceControlStore.preferences.branchReadOnly"
					:content="i18n.baseText('readOnlyEnv.cantAdd.any')"
				>
					<div style="display: flex; gap: var(--spacing--xs); align-items: center">
						<ReadyToRunButton :has-active-callouts="props.hasActiveCallouts" />
						<ProjectCreateResource
							data-test-id="add-resource-buttons"
							:actions="menu"
							:disabled="sourceControlStore.preferences.branchReadOnly"
							@action="onSelect"
						>
							<N8nButton
								:data-test-id="`add-resource-${selectedMainButtonType}`"
								v-bind="mainButtonConfig"
								@click="onSelect(selectedMainButtonType)"
							/>
						</ProjectCreateResource>
					</div>
				</N8nTooltip>
			</div>
		</div>
		<slot></slot>
		<div :class="$style.actions">
			<ProjectTabs
				:page-type="pageType"
				:show-executions="!projectPages.isSharedSubPage"
				:show-settings="showSettings"
				:additional-tabs="customProjectTabs"
			/>
		</div>
	</div>
</template>

<style lang="scss" module>
.projectHeader {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	min-height: var(--spacing--3xl);
}

.projectDetails {
	display: flex;
	align-items: center;
}

.actions {
	padding: var(--spacing--2xs) 0 var(--spacing--xs);
}

.projectDescriptionWrapper {
	position: relative;
	display: inline-block;

	&:hover .tooltip {
		display: block;
	}
}

.tooltip {
	display: none;
	position: absolute;
	top: 0;
	left: calc(-1 * var(--spacing--3xs));
	background-color: var(--color--background--light-2);
	padding: 0 var(--spacing--3xs) var(--spacing--3xs);
	z-index: 10;
	white-space: normal;
	border-radius: 6px;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

@include mixins.breakpoint('xs-only') {
	.projectHeader {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--spacing--xs);
	}

	.headerActions {
		margin-left: auto;
	}
}
</style>
